package kdiapo;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.Iterator;

import javax.swing.*;

import Model.ElementSlide;
import Model.ImageElement;
import Model.ListSlideModel;
import Model.SlideContent;
import Model.TextElement;
import Model.VideoElement;
import View.ImageView;
import View.TextView;
import View.VideoView;
import oscP5.*;
import processing.core.PApplet;
import netP5.*;


public class SlideShow extends JFrame 
{
	private static SlideShow myInstance;
	
	private int currentIndex = 0;	
	private JPanel panel;	
	private JTextArea text;	
	private SlideContent slideContent;
	Timer time;
	private ListSlideModel myModel;
	private OscP5 oscP5;
	private NetAddress makeControllerAddress;
	private KeyboardFocusManager manager;
	private MyDispatcher dispatcher;
	private VideoView currentVideo;
	private ImageView currentImage;
	private boolean isZoomed;
	private Timer timer;
	private boolean latency = true;
	private boolean security = false;

	private SlideShow(ListSlideModel model)
	{
		super("KDiapo Presentation Mode");
		//setSize(850, 650);
		setUndecorated(true);
		setSize(getToolkit().getScreenSize());
		//setExtendedState(JFrame.MAXIMIZED_BOTH );

		panel = new JPanel();
		panel.setBackground(Color.white);		
		
		myModel = model;
		
		if (!model.getListSlide().isEmpty())
		{	
			setLayoutForCurrentSlide();
			//System.out.println(model.getListSlide());
			slideContent = model.getListSlide().get(0);			
			insertSlideShow();		
			panel.setBackground(slideContent.getSlideBackgroundColor());
		}
		else {
			text = new JTextArea("No slide to show");
			text.setEditable(false);
			panel.add(text,BorderLayout.CENTER);
		}
		
		this.getContentPane().add(panel);
		
		//setVisible(true);
		
		oscP5 = new OscP5(this,10000);
		makeControllerAddress = new NetAddress("127.0.0.1", 10000);
		
		System.out.println("Slideshow : slide 0");
		manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
		dispatcher = new MyDispatcher();
		manager.addKeyEventDispatcher(dispatcher); 
		
		/*Embedded applet = new Embedded();
		//applet.setVisible(true);
		applet.init();
		applet.setBounds(getToolkit().getScreenSize().width-400, getToolkit().getScreenSize().height-400, 400, 400);
		panel.add(applet);*/
		
		// timer to disable two quickly detected consecutive movements
		timer = createTimer();
		timer.start();
	    
	}
	
	public void setLayoutForCurrentSlide(){
    	javax.swing.GroupLayout pSlideLayout = new javax.swing.GroupLayout(panel);
		panel.setLayout(pSlideLayout);
        pSlideLayout.setHorizontalGroup(
        		pSlideLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 800, Short.MAX_VALUE)
        );
        pSlideLayout.setVerticalGroup(
        	pSlideLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 580, Short.MAX_VALUE)
            );
    }
	
	public void init(){
		currentIndex = 0;
		if (!myModel.getListSlide().isEmpty()){			
			displaySlide(currentIndex);		
		}
		else {
			panel.removeAll();			
			this.remove(panel);			
			panel = new JPanel();
			panel.setBackground(Color.white);
			text = new JTextArea("No slide to show");
			text.setEditable(false);
			panel.add(text,BorderLayout.CENTER);
			this.getContentPane().add(panel);
		}
	}
	
	public void displaySlide(int slideNb){
		slideContent = myModel.getListSlide().get(slideNb);
		panel.removeAll();			
		this.remove(panel);			
		panel = new JPanel();
		setLayoutForCurrentSlide();
		panel.setBackground(slideContent.getSlideBackgroundColor());	
		insertSlideShow();	
		this.getContentPane().add(panel);
		panel.revalidate();
		panel.repaint();			
		System.out.println("Slideshow : slide "+slideNb);
	}
	
	public void insertSlideShow(){
		Iterator<ElementSlide> itr = slideContent.getListElements().iterator();
	    while (itr.hasNext()) {
	    	ElementSlide element = itr.next();
	    	// Text Element
	    	if(element instanceof TextElement){
	    		TextElement elt = (TextElement) element;
	    		TextView area = new TextView(this,elt.getNumElement(),
	    				elt.getPosX(),elt.getPosY(),elt.getWidth(),elt.getHeight(),elt.getBackgroundColor()
	    				,slideContent.getSlideFontColor(),slideContent.getSlideFont());
	    		area.setTextValue(elt.getTextValue());
	    		panel.add(area.getResizer(),elt.getNumElement());
	    	}
	    	// Image Element
	    	if(element instanceof ImageElement){
	    		ImageElement elt = (ImageElement) element;
	    		ImageView area = new ImageView(this,elt.getNumElement(),
	    				elt.getPath(),elt.getPosX(),elt.getPosY(),elt.getWidth(),elt.getHeight());
	    		currentImage = area;
	    		isZoomed = false;
	    		panel.add(area.getResizer(),elt.getNumElement());
	    	}
	    	// Video Element
	    	if(element instanceof VideoElement){
	    		VideoElement elt = (VideoElement) element;
	    		File f = new File(elt.getPath());
	    		
	    		VideoView area = new VideoView(this,elt.getNumElement(),f,elt.getPosX(),
	    				elt.getPosY(),elt.getWidth(),elt.getHeight());
	    		currentVideo = area;
	    		//insertion of the element in the view
	    		panel.add(area.getResizer(),elt.getNumElement());
	    	}
	    }
		
	}
	
	void oscEvent(OscMessage theOscMessage){
		// compare the incoming address to the address we asked for
		System.out.println("message : "+theOscMessage);
		if(slideContent!=null){
			if( (theOscMessage.addrPattern().equals("/next")) && latency)	{
				latency = false;
				currentIndex++;	
				// if there were no slide or if we have ended the presentation
				if (currentIndex >= myModel.getNbSlide()){
					panel.removeAll();			
					this.remove(panel);			
					panel = new JPanel();
					panel.setBackground(Color.white);			
					text = new JTextArea();
					text.setText("End of the presentation");
					panel.add(text, BorderLayout.CENTER);			
					this.getContentPane().add(panel);
					panel.revalidate();
					panel.repaint();	
					if (currentIndex == myModel.getNbSlide()+1)
						currentIndex--;	
					System.out.println("Slideshow : end slide (index = "+currentIndex+")");
				}
				else {
					displaySlide(currentIndex);
				}
			}
			else if( (theOscMessage.addrPattern().equals("/previous")) && latency)	{
				latency = false;
				currentIndex--;
				if (currentIndex >= 0){		
					displaySlide(currentIndex);
				}
				else {
					panel.removeAll();			
					this.remove(panel);			
					panel = new JPanel();
					panel.setBackground(Color.white);			
					text = new JTextArea();
					if (myModel.getNbSlide() == 0)
						text.setText("No slide to show");
					else
						text.setText("Beginning of the presentation");
					panel.add(text, BorderLayout.CENTER);			
					this.getContentPane().add(panel);
					panel.revalidate();
					panel.repaint();
					if (currentIndex == -2)
						currentIndex++;	
					System.out.println("Slideshow : no slide to show (index = "+currentIndex+")");
				}
			}
			else if(theOscMessage.addrPattern().equals("/pause_resume")){
				latency = false;
				if (slideContent.isHasVideo()){
					System.out.println("Slide has video");
					currentVideo.pause();
				}
			}
			else if(theOscMessage.addrPattern().equals("/zoom")){
				latency  = false;
				if (slideContent.isHasImage() && !isZoomed){
					int newWidth = 1;
					int newHeight = 1;
					if (currentImage.getWidth() >= currentImage.getHeight()){
						newWidth = panel.getWidth() - 40;					
						newHeight = newWidth * currentImage.getHeight() / currentImage.getWidth();
						if (newHeight >= panel.getHeight() - 40){
							newHeight = panel.getHeight() - 40;
							newWidth = newHeight * currentImage.getWidth() / currentImage.getHeight();
						}						
					}
					else{
						newHeight = panel.getHeight() - 40;					
						newWidth = newHeight * currentImage.getWidth() / currentImage.getHeight();
						if (newWidth >= panel.getWidth() - 40){
							newWidth = panel.getWidth() - 40;
							newHeight = newWidth * currentImage.getHeight() / currentImage.getWidth();
						}
					}
					int newX = panel.getWidth() / 2 - newWidth / 2;
					int newY = panel.getHeight() / 2 - newHeight / 2;
					currentImage.getResizer().setBounds(newX, newY, newWidth, newHeight);
					currentImage.getResizer().revalidate();
					currentImage.getResizer().repaint();
					panel.setComponentZOrder(currentImage.getResizer(), 0);				
					isZoomed = true;
				}			
			}
			else if(theOscMessage.addrPattern().equals("/unzoom")){
				if (slideContent.isHasImage() && isZoomed){
					displaySlide(currentIndex);
					isZoomed = false;
				}
			}
			else if(theOscMessage.addrPattern().equals("/hand_up")){
				String res = myModel.getActionFor("/hand_up");
				System.out.println("redirection to "+res);
				if(!res.equals("")){
					OscMessage myMessage = new OscMessage("/"+res);
		        	oscP5.send(myMessage, makeControllerAddress);
				}
			}
			else if(theOscMessage.addrPattern().equals("/hand_away")){
				String res = myModel.getActionFor("/hand_away");
				System.out.println("redirection to "+res);
				if(!res.equals("")){
					OscMessage myMessage = new OscMessage("/"+res);
		        	oscP5.send(myMessage, makeControllerAddress);
				}
			}
			else if(theOscMessage.addrPattern().equals("/hand_approach")){
				String res = myModel.getActionFor("/hand_approach");
				System.out.println("redirection to "+res);
				if(!res.equals("")){
					OscMessage myMessage = new OscMessage("/"+res);
		        	oscP5.send(myMessage, makeControllerAddress);
				}
			}
			else if(theOscMessage.addrPattern().equals("/static_hand")){
				String res = myModel.getActionFor("/static_hand");
				System.out.println("redirection to "+res);
				if(!res.equals("")){
					OscMessage myMessage = new OscMessage("/"+res);
		        	oscP5.send(myMessage, makeControllerAddress);
				}
			}
		}
	}
	
	
	
	private class MyDispatcher implements KeyEventDispatcher {
	    public boolean dispatchKeyEvent(KeyEvent e) {
	        if (e.getID() == KeyEvent.KEY_PRESSED) {
	            //System.out.println("Key Pressed("+e.getKeyChar()+")");
	        } 
	        else if (e.getID() == KeyEvent.KEY_RELEASED) {
	            System.out.println("keyCode : "+e.getKeyCode());
	            // right arrow key
	            if (e.getKeyCode() == 39){
	            	System.out.println("next detected!");
	            	OscMessage myMessage = new OscMessage("/next");
	            	oscP5.send(myMessage, makeControllerAddress);
	            }
	            // left arrow key
	            else if (e.getKeyCode() == 37){
	            	System.out.println("previous detected!");
	            	OscMessage myMessage = new OscMessage("/previous");
	            	oscP5.send(myMessage, makeControllerAddress);
	            }
	            // space bar
	            else if (e.getKeyCode() == 32){
	            	System.out.println("pause/resume detected!");
	            	OscMessage myMessage = new OscMessage("/pause_resume");
	            	oscP5.send(myMessage, makeControllerAddress);
	            }
	            // + 
	            else if (e.getKeyCode() == 107){
	            	
	            	System.out.println("zoom detected! ");
	            	OscMessage myMessage = new OscMessage("/zoom");
	            	oscP5.send(myMessage, makeControllerAddress);
	            }
	            // - 
	            else if (e.getKeyCode() == 109){
	            	System.out.println("unzoom detected!");
	            	OscMessage myMessage = new OscMessage("/unzoom");
	            	oscP5.send(myMessage, makeControllerAddress);
	            }
	            // p (plus) 
	            else if (e.getKeyCode() == 80){
	            	
	            	System.out.println("zoom detected! ");
	            	OscMessage myMessage = new OscMessage("/zoom");
	            	oscP5.send(myMessage, makeControllerAddress);
	            }
	            // m (minus) 
	            else if (e.getKeyCode() == 77){
	            	System.out.println("unzoom detected!");
	            	OscMessage myMessage = new OscMessage("/unzoom");
	            	oscP5.send(myMessage, makeControllerAddress);
	            }
	            // escape
	            else if(e.getKeyCode() == 27){
	            	myInstance.setVisible(false);
	            	dispose();
	            }
	        } else if (e.getID() == KeyEvent.KEY_TYPED) {
	            //System.out.println("Key Typed");
	        }
	        return false;
	    }
	}
	
	public static SlideShow getInstance(ListSlideModel model){
		if (myInstance == null)
			myInstance = new SlideShow(model);
		else{
			myInstance.setModel(model);
			myInstance.init();
		}
		return myInstance;
	}	
	
	public void setModel(ListSlideModel model){
		myModel = model;
	}
	
	private Timer createTimer ()
	  {
	    // timer listener
	    ActionListener action = new ActionListener ()
	      {
	    	// timer to disable two quickly detected consecutive movements
	        public void actionPerformed (ActionEvent event)
	        {
	        	// security margin in case the message is received just before the "click" occurs
	        	if (security == false){
	        		security = true;
	        	}
	        	if (security == true){
	        		if (latency == false){
	        			latency = true;
	        		}
	        		security = false;
	        	}
	        }
	      };
	    return new Timer (3000, action);
	  }  
}
